#include "Board.h"
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <stdio.h>
#include <string>
#include <sstream>
#include "PChess.h"

using namespace std;

// prints moves being examined if true
#define verbose 0
#define d(var) if (verbose) cout << #var << " = " << var << ", "

Board::Board()
{
    // Default constructor, set up a new game board
    newGame();
}

Board::Board(string boardLayout)
{
    // Default constructor, set up a new game board
	if (boardLayout.compare("") == 0)	// if we were passed in the empty string
		newGame();						// use standard board layout
	else
		newGame(boardLayout);			// use layout that was passed in
}

// Board evaluation function
int Board::evaluate()
{
	return 10 * evaluateMaterial() + 3 * evaluateCastling() + evaluateDevelopment() + evaluatePawns() + evaluateMobility()
			+ evaluateQueenMovement();
}

int Board::evaluateMaterial()
{
	 int score = 0;
	int value = 0;

	for (int row = 0; row < 8; row++)
	{
		for (int col = 0; col < 8; col++)
		{
			switch(abs(pieces[row][col]))
			{
					// Pawns
				case 1: value=10; break;
					// Bishops
				case 2: value=30; break;
				// Knights
				case 3: value=30; break;
				// Rooks
				case 4: value=50; break;
				// Queens
				case 5: value=90; break;
				// Kings
				case 6: value=10000; break;

				default: value=0; break;
			}
			if(pieces[row][col]>0)
				score += value; // White's piece
			else
				score -= value; // Black's piece
		}
	}

	return score;
}

int Board::evaluateCastling()
{
	int score = 0;
	// reduce score for a side when they lose the ability to castle
	if (!whiteHasCastled)
	{
		if (!whiteCanCastleKingside && !whiteCanCastleQueenside)	// white has lost ability to castle completely
			score -= 10;
		else if (!whiteCanCastleKingside)					// black can only castle queenside
			score -= 3;
		else if (!whiteCanCastleQueenside)					// black can only castle kingside
			score -= 2;
	}
	else
		score += 30;		// white has castled
	if (!blackHasCastled)
	{
		if (!blackCanCastleKingside && !blackCanCastleQueenside)	// black has lost ability to castle completely
			score += 10;
		else if (!blackCanCastleKingside)		// black can only castle queenside
			score += 3;
		else if (!blackCanCastleQueenside)		// black can only castle kingside
			score += 2;
	}
	else
		score -= 30;		// black has castled

	return score;
}

int Board::evaluateDevelopment()
{
	int knightDevlopmentWeight = 1;
	int kingQueenPawnDevelopmentWeight = 2;


	int score = 0;
	// check if knights are still in original positions... bad development, and
	// can block rooks
	if (pieces[0][1] == KNIGHT)
		score -= knightDevlopmentWeight * 10;
	if (pieces[0][6] == KNIGHT)
		score -= knightDevlopmentWeight * 10;
	if (pieces[8][1] == (KNIGHT * -1))
			score += knightDevlopmentWeight * 10;
	if (pieces[8][6] == (KNIGHT * -1))
		score += knightDevlopmentWeight * 10;

	// check if king and queen pawns are still in original positions
	if (pieces[1][3] == PAWN)
		score -= kingQueenPawnDevelopmentWeight * 7;
	if (pieces[1][4] == PAWN)
		score -= kingQueenPawnDevelopmentWeight * 10;
	if (pieces[7][3] == (PAWN * -1))
			score += kingQueenPawnDevelopmentWeight * 7;
	if (pieces[7][4] == (PAWN * -1))
		score += kingQueenPawnDevelopmentWeight * 10;

	return score;
}

int Board::evaluatePawns()
{
	int penaltyPerExtraPawn = 10;
	int isolatedPawnPenalty = 10;
	int score = 0;

	bool hasPawn[2][8];		// store whether there is a pawn in each column for both colors
	// in order to evaluate isolated pawns

	// unlike the usual chess board traversal, we go COLUMN by column here
	// as we are counting the number of pawns of the same color in each column
	for (int col = 0; col < 8; col++)
	{
		int whitePawnsSoFar = 0, blackPawnsSoFar = 0;
		for (int row = 0; row < 8; row++)
		{
			if (pieces[row][col] == PAWN)	// white pawn
			{
				whitePawnsSoFar++;
				hasPawn[1][col] = true;
			}
			else if (pieces[row][col] == (PAWN * -1))	// black pawn
			{
				blackPawnsSoFar++;
				hasPawn[0][col] = true;
			}
		}
		// for each extra pawn in a column increase the penalty
		score -= max(whitePawnsSoFar - 1, 0) * penaltyPerExtraPawn;
		score += max(blackPawnsSoFar - 1, 0) * penaltyPerExtraPawn;
	}

	int numBlackIsolatedPawns = 0, numWhiteIsloatedPawns = 0;

	// check for isolated pawns
	// for each column, check if pawn has a neighbor
	for (int col = 0; col < 8; col++)
	{
		for (int curIsWhite = 0; curIsWhite <= 1; curIsWhite++)
		{
			if (hasPawn[curIsWhite][col])
				if (!((col == 0) || (hasPawn[curIsWhite][col - 1]) || ((col == 7) || hasPawn[curIsWhite][col + 1])))		// if neither neighbor column has a pawn
					// note: we skip the neighbor check at the peripheries (this is what the (col == 0) and (col == 7) parts are for)
				{
					if (curIsWhite)					// it is an isolated pawn
						numWhiteIsloatedPawns++;
					else
						numBlackIsolatedPawns++;
				}
		}

	}

	// add in the isolated pawn penalties
	score -= numWhiteIsloatedPawns * isolatedPawnPenalty;
	score += numBlackIsolatedPawns * isolatedPawnPenalty;

	return score;
}

int Board::evaluateMobility()
{
	int score = 0;

	int knightPenalty = 3;

	for (int row = 0; row < 8; row++)
		for (int col = 0; col < 8; col++)
		{
			int currentPiece = pieces[row][col];
			switch (abs(currentPiece))
			{
			case KNIGHT:		// penalty for knights on the periphery
				if ((col == 0) || (col == 7))		// outermost column
				{
					if (currentPiece > 0)		// white piece
						score -= knightPenalty;
					else
						score += knightPenalty;
				}
				if ((row == 0) || (row == 7))		// outermost row. Keep seperate from column because it is worse if we are in a corner
				{
					if (currentPiece > 0)		// white piece
						score -= knightPenalty;
					else
						score += knightPenalty;
				}
				break;
			}
		}
	if (verbose)
		cout << "mobility = " << score << ", ";
	return score;
}

/*
 * Check whether queen moves before other pieces have been developed
 */
int Board::evaluateQueenMovement()
{
	return 0;
	int prematureQueenMovementPenalty = 10;
	int undevelopedPenalty = 3;

	int score = 0;
	bool whiteQueenHasMoved, blackQueenHasMoved;
	int numUndevelopedWhitePieces = 0, numUndevelopedBlackPieces = 0;

	for (int row = 0; row <= 7; row += 7)		// for rows 0 and 7
	{
		int colorMultiplier = (row == 0) ? 1 : -1;
		for (int col = 0; col < 8; col++)
		{
			int currentPiece = pieces[row][col];
			switch (col)
			{
			case 1:
			case 6:
				if (currentPiece == (colorMultiplier * KNIGHT))		// this is a knight in its original position
				{
					if (currentPiece > 0)
						numUndevelopedWhitePieces++;
					else
						numUndevelopedBlackPieces++;
				}
				break;
			case 2:
			case 5:
				if (currentPiece == (colorMultiplier * BISHOP))		// this is a bishop in its original position
				{
					if (currentPiece > 0)
						numUndevelopedWhitePieces++;
					else
						numUndevelopedBlackPieces++;
				}
				break;
			case 3:
			// store whether queen has moved
				if (currentPiece > 0)
					whiteQueenHasMoved = (currentPiece == (colorMultiplier * QUEEN));
				else
					blackQueenHasMoved = (currentPiece == (colorMultiplier * QUEEN));
			break;
			}
		}
	}

	if (whiteQueenHasMoved && (numUndevelopedWhitePieces > 3))
		score -= prematureQueenMovementPenalty;
	if (blackQueenHasMoved && (numUndevelopedBlackPieces > 3))
		score += prematureQueenMovementPenalty;

	score -= numUndevelopedWhitePieces * undevelopedPenalty;
	score += numUndevelopedBlackPieces * undevelopedPenalty;

	d(numUndevelopedBlackPieces); d(numUndevelopedWhitePieces);

	if (verbose)
		cout << "queen score = " << score << endl;

	return score;
}


/*
 * A primitive way to print moves... not accurate
 * in special cases because it never prints the from square
 * (e.g. would not correctly print exd4 for pawn, or RAxd4)
 */
void Board::printMove(int piece, int row, int col)
{
	bool isCaptureMove = pieces[row][col];		// is a capture if there is a piece in the "to" square
	string pieceChar = "";		// leave blank if piece is pawn
	switch (abs(piece))
	{
	case KNIGHT: pieceChar = 'N'; break;
	case BISHOP: pieceChar = 'B'; break;
	case ROOK: pieceChar = 'R'; break;
	case QUEEN: pieceChar = 'Q'; break;
	case KING: pieceChar = 'K'; break;
	}

	stringstream ss;
	string colString;
	char c = col + 'a';
	ss << c;
	ss >> colString;

	cout << pieceChar << ((isCaptureMove) ? "x" : "") << colString << (row + 1) << endl;
}

void Board::printCastleMove(bool playerIsWhite, bool kingside)
{
	cout << ((playerIsWhite) ? "white " : "black ");
	if (kingside)
		cout << "0-0\n";
	else
		cout << "0-0-0\n";
}

void Board::initialValues()
{
    // Allow players to castle to both sides
    blackCanCastleQueenside = true;
    blackCanCastleKingside = true;
    whiteCanCastleQueenside = true;
    whiteCanCastleKingside = true;

    whiteHasCastled = false;
    blackHasCastled = false;

    status = 0;
    ply = 1;		// start with move number 1
}

Board& Board::operator=(const Board& other)
{
	for (int row = 0; row < 8; row++)
			for (int col = 0; col < 8; col++)
				pieces[row][col] = other.pieces[row][col];

	blackCanCastleQueenside = other.blackCanCastleQueenside;
	blackCanCastleKingside = other.blackCanCastleKingside;
	whiteCanCastleQueenside = other.whiteCanCastleQueenside;
	whiteCanCastleKingside = other.whiteCanCastleKingside;

	whiteHasCastled = other.whiteHasCastled;
	blackHasCastled = other.blackHasCastled;

	status = other.status;
	ply = other.ply;		// start with move number 1

	return *this;
}

/*
 * Print the board top to bottom (from white's perspective)
 */
void Board::printBoard()
{
	d(status);
	
	for (int row = 7; row >= 0; row--)
	{
            cout << (row+1) << " ";
               	for (int col = 0; col < 8; col++)
		{
			printPiece(pieces[row][col]);
		}
		cout << endl;
	}
        cout << "\n  abcdefgh" << std::endl << std::endl;
}

/*
 * Print a specific piece's character
 */
void Board::printPiece(int piece)
{
    char output;
    int pieceType = abs(piece);
    switch(pieceType)
    {
        case PAWN: output='p'; break;
        case ROOK: output='r'; break;
        case KNIGHT: output='n'; break;
        case BISHOP: output='b'; break;
        case QUEEN: output='q'; break;
        case KING: output='k'; break;
        case EMPTY: output='-'; break;

        default: output='?'; break;
    }

    if (piece > 0)		// white piece
    	output = toupper(output);

    std::cout << output;
}

/*
 * Sets up an initial chess position on the board
 */
void Board::newGame()
{
	for (int row = 0; row < 8; row++)
		for (int col = 0; col < 8; col++)
		{
			// PAWN ROWS
			if (row == 1)
				pieces[row][col] = PAWN;
			else if (row == 6)
				pieces[row][col] = -1 * PAWN;
			// PIECE ROWS
			else if ((row == 0) || (row == 7))
			{
				int newPiece;			// store the piece type (without color)
				switch (col)
				{
				case 0:
				case 7:
					newPiece = ROOK;		// ROOKS on outer squares
					break;
				case 1:
				case 6:
					newPiece = KNIGHT;
					break;
				case 2:
				case 5:
					newPiece = BISHOP;
					break;

				// KING/QUEEN LOGIC
				case 3:
						newPiece = QUEEN;
					break;
				case 4:
						newPiece = KING;
					break;

				}
				if (row == 7)				// top row
					newPiece *= -1;		// change to black piece

				pieces[row][col] = newPiece;
			}
			// EMPTY ROWS
			else
				pieces[row][col] = 0;
		}
    initialValues();
}

/*
 * Uses standard FEN notation (see http://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation)
 * to initialize a new board
 */
void Board::newGame(string boardLayout)
{
	char cur;
	int i = 0;		// keep track of the character we're on as we iterate through
	int column;
	for (int line = 7; line >= 0; line--)
	{
		column = 0;			// at the beginning of each row, start back at column 0
		while ((cur = boardLayout[i++]) != '\n')	// read char by char until we reach a newline
		{
			switch (tolower(cur))		// tolower will leave numbers alone, convert chars to lowercase so we can group them better
			{
			case 'p':
				pieces[line][column++] = PAWN * ((isupper(cur)) ? 1 : -1); break;
			case 'r':
				pieces[line][column++] = ROOK * ((isupper(cur)) ? 1 : -1); break;
			case 'n':
				pieces[line][column++] = KNIGHT * ((isupper(cur)) ? 1 : -1); break;
			case 'b':
				pieces[line][column++] = BISHOP * ((isupper(cur)) ? 1 : -1); break;
			case 'q':
				pieces[line][column++] = QUEEN * ((isupper(cur)) ? 1 : -1); break;
			case 'k':
				pieces[line][column++] = KING * ((isupper(cur)) ? 1 : -1); break;
			default:
				char num[2] = {cur, '\0'};		// atoi won't allow you to parse a single char so we need to use a cstring
				int numBlanks = atoi(num);		// parse current char as a number if it doesn't match one of the chars
				while (numBlanks > 0 && column < 8)
				{
					pieces[line][column++] = EMPTY;
					numBlanks--;
				}
				break;
			}
		}
	}
	// TODO parse initial values as well, as in standard FEN notation (see http://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation)
    initialValues();
    removeCastleAbility(true);
    removeCastleAbility(false);
}

/*
 * check if move is legal
 * if it is, add it to vector
 */
void Board::addMove(int piece, int fromRow, int fromCol, int toRow, int toCol, vector<Board *> &possibleMoves)
{
	Board *newBoard = new Board(*this);
	newBoard->ply++;

	newBoard->pieces[fromRow][fromCol] = EMPTY;		// empty the square we're moving from
	newBoard->pieces[toRow][toCol] = piece;			// move the piece to its new position
	// add to game tree IF it is a legal position (you're not putting/leaving your king in check)
	if (!newBoard->isInCheck(piece))
	{
		int pieceType = abs(piece);		// store the type of piece (without color)
		// update canCastle bools when a king or rook is moved
		if (pieceType == KING)
		{
			// set canCastle to false for king & queen sides for this color
			if (piece > 0)	// white
				removeCastleAbility(true);
			else
				removeCastleAbility(false);
		}
		else if (pieceType == ROOK)
		{
			if (fromCol == 7)		// if this rook is the kingside rook in its starting square
			{
				if (piece > 0)
					whiteCanCastleKingside = false;
				else
					blackCanCastleKingside = false;
			}
			else if (fromCol == 0)		// if this rook is the queenside rook in its starting square
			{
				if (piece > 0)
					whiteCanCastleQueenside = false;
				else
					blackCanCastleQueenside = false;
			}
		}
		else if (pieceType == PAWN)		// PROMOTIONS
		{
			// check if a pawn has moved to the back rank
			if ((toRow == 7) && (piece > 0))		// moving to the 8th rank && white
			{
				// add all possible promotions to the vector
				newBoard->pieces[toRow][toCol] = QUEEN;
				possibleMoves.push_back(newBoard);
				newBoard = new Board(*newBoard);		// copy the new board
				newBoard->pieces[toRow][toCol] = ROOK;
				possibleMoves.push_back(newBoard);
				newBoard = new Board(*newBoard);
				newBoard->pieces[toRow][toCol] = KNIGHT;
				possibleMoves.push_back(newBoard);
				newBoard = new Board(*newBoard);
				newBoard->pieces[toRow][toCol] = BISHOP;
				possibleMoves.push_back(newBoard);

				return;					// end function as nothing left to do with this position anymore
			}
			else if ((toRow == 0) && (piece < 0))		// moving to the 1st rank && black
			{
				// add all possible promotions to the vector
				newBoard->pieces[toRow][toCol] = QUEEN * -1;
				possibleMoves.push_back(newBoard);
				newBoard = new Board(*newBoard);		// copy the new board
				newBoard->pieces[toRow][toCol] = ROOK * -1;
				possibleMoves.push_back(newBoard);
				newBoard = new Board(*newBoard);
				newBoard->pieces[toRow][toCol] = KNIGHT * -1;
				possibleMoves.push_back(newBoard);
				newBoard = new Board(*newBoard);
				newBoard->pieces[toRow][toCol] = BISHOP * -1;
				possibleMoves.push_back(newBoard);

				return;					// end function as nothing left to do with this position anymore
			}
		}
		if (newBoard->isInCheck(piece * -1))		// check if the opposite side is in check
			newBoard->status = (((piece * -1) > 0) ? WHITE_CHECK : BLACK_CHECK);			// tag the board accordingly if it is
		else
			newBoard->status = 0;		// otherwise, no one is in check (as a legal move must move a player out of check)
		possibleMoves.push_back(newBoard);				// add to the tree of possible moves
		if (verbose)
		{
			printMove(piece, toRow, toCol);
			newBoard->printBoard();
		}
	}
	else
	{
		if (verbose)
		{
			cout << "CHECK-------------->\n";
			newBoard->printBoard();
		}
		delete newBoard;
	}
}

// sets canCastleKingside and queenside to false for player
void Board::removeCastleAbility(bool playerIsWhite)
{
	if (playerIsWhite)
	{
		whiteCanCastleKingside = false;
		whiteCanCastleQueenside = false;
	}
	else
	{
		blackCanCastleKingside = false;
		blackCanCastleQueenside = false;
	}
}

/*
 * check if move is legal
 * if it is, add it to vector
 */
void Board::addCastleMove(bool playerIsWhite, bool kingside, vector<Board *> &possibleMoves)
{
	Board *newBoard = new Board(*this);

	newBoard->castle(playerIsWhite, kingside);
	newBoard->removeCastleAbility(playerIsWhite);	// player can only castle once
	// no need to check if this puts the king in check as canCastle already checks
	possibleMoves.push_back(newBoard);
	if (verbose)
		printCastleMove(playerIsWhite, kingside);
}

bool onBoard(int row, int col)
{
	return (row >= 0 && row < 8 &&
			col >= 0 && col < 8);
}

void Board::generateMoves(vector<Board *> &possibleMoves, int ply)
{
    bool playerIsWhite = (ply % 2 == 0);
    
		/*for (each piece in position)
		 	 for (each possible move with piece)
			 {
				 if (position generated from move) is
				 ((ON BOARD) && (NOT ON TOP OF A PIECE OF SAME COLOR))
				 	 create new position
				 	 if (new position isLegalMove)
				 	 	 add new position to legalMoves with current square empty, new square updated
				 	 else
				 	 	 release new position memory
			 }
		 */

		// add any possible castle moves for
		// the player whose move it is
		if (canCastle(playerIsWhite, true))
		{
			addCastleMove(playerIsWhite, true, possibleMoves);
		}
		if (canCastle(playerIsWhite, false))
		{
			addCastleMove(playerIsWhite, false, possibleMoves);
		}

		for (int row = 0; row < 8; row++)
			for (int col = 0; col < 8; col++)
			{
				int piece = pieces[row][col];
				bool isWhite = piece > 0;

				// Can only move pieces that belong to you
				if((isWhite && !playerIsWhite) || (!isWhite && playerIsWhite))
					continue;


				int newRow, newCol; // store each new move being examined

				switch (abs(piece))		// switch on the piece type, independent of color
				{
				case EMPTY:
					// do nothing
					break;
				case PAWN:
					// 2-square moves
					// don't need to check if on board since it's impossible
					if ((isWhite && (row == 1)) || (!isWhite && (row == 6)))
					{
						newCol = col;		// stay in original column
						bool pathEmpty;		// make sure we're not "leaping" over a piece
						if (isWhite)
						{
							newRow = row + 2;
							pathEmpty = (pieces[row + 1][newCol] == EMPTY);
						}
						else
						{
							newRow = row - 2;
							pathEmpty = (pieces[row - 1][newCol] == EMPTY);
						}

						// pawns only take diagonally
						// don't add position if on top of ANY piece

						if (pathEmpty && (pieces[newRow][newCol] == EMPTY)) 	// new position is EMPTY
						{
							addMove(piece, row, col, newRow, newCol, possibleMoves);
						}
					}
					// 1-square moves TODO
					// col stays same, row +/- 1
					newCol = col;
					if (isWhite)
						newRow = row + 1;
					else
						newRow = row - 1;
						if (onBoard(newRow, newCol) && pieces[newRow][newCol]==EMPTY)		// if the new square is on the board AND empty
					{
						addMove(piece, row, col, newRow, newCol, possibleMoves);
					}
					// Left diagonal capture
					newCol = col-1;
					if (isWhite)
						newRow = row + 1;
					else
						newRow = row - 1;
					if(onBoard(newRow, newCol))
					{   // There must be an opponents pieces in that position for this move
						if((isWhite && pieces[newRow][newCol] < 0) || (!isWhite && pieces[newRow][newCol] > 0))
						addMove(piece, row, col, newRow, newCol, possibleMoves);
					}
					// Right diagonal capture
					newCol = col+1;
					if(onBoard(newRow, newCol))
					{   // There must be an opponents pieces in that position for this move
						if((isWhite && pieces[newRow][newCol] < 0) || (!isWhite && pieces[newRow][newCol] > 0))
							addMove(piece, row, col, newRow, newCol, possibleMoves);
					}
					// TODO en passant moves
					break;
				case BISHOP:
					for (int north = 0; north <=1; north++)
						for (int east = 0; east <=1; east++)
						{
							bool lastWasOnBoard;
							newCol = col; newRow = row;	// reset starting points
							do
							{
								// iterates through NE, SE, SW, and NW directions
								if (north) newCol++;
								else newCol--;
								if (east) newRow++;
								else newRow--;

								// add move if:
								// 1) square is on the board AND
								// 2) square is empty OR occupied by OPPOSITE color
								lastWasOnBoard = onBoard(newRow, newCol);
								if ((lastWasOnBoard) && ((isWhite && pieces[newRow][newCol] <= 0) || (!isWhite && pieces[newRow][newCol] >= 0)))
									addMove(piece, row, col, newRow, newCol, possibleMoves);
							// if a piece goes off the board or is blocked (by either color), stop checking that path
							} while (lastWasOnBoard && (pieces[newRow][newCol] == EMPTY));
						}

					break;
				case KNIGHT:
					// for each direction:
					for (int north = 0; north <= 1; north++)
						for (int east = 0; east <= 1; east++)
							// knights move by 2 in a column and 1 in a row, or vice versa
							// columnBy2 represents which of these options we're trying
							for (int columnBy2 = 0; columnBy2 <= 1; columnBy2++)
							{
								int addToCol = ((columnBy2) ? 2 : 1);
								int addToRow = ((columnBy2) ? 1 : 2);
								if (north)
									newRow = row + addToRow;
								else
									newRow = row - addToRow;
								if (east)
									newCol = col + addToCol;
								else
									newCol = col - addToCol;
								// add move if:
								// 1) square is on the board AND
								// 2) square is empty OR occupied by OPPOSITE color
								if (onBoard(newRow, newCol) && ((isWhite && pieces[newRow][newCol] <= 0) || (!isWhite && pieces[newRow][newCol] >= 0)))
									addMove(piece, row, col, newRow, newCol, possibleMoves);
							}

					break;
				case ROOK:
					for (int direction = 0; direction < 4; direction++)
					{
						bool lastWasOnBoard;
						newCol = col; newRow = row;	// reset starting points
						do
						{
							// iterates through N, S, E, W
							switch (direction)
							{
							case 0: newRow++; break;	// NORTH
							case 1: newRow--; break;	// SOUTH
							case 2: newCol++; break;	// EAST
							case 3: newCol--; break;	// WEST
							}

							// add move if:
							// 1) square is on the board AND
							// 2) square is empty OR occupied by OPPOSITE color
							lastWasOnBoard = onBoard(newRow, newCol);
							if ((lastWasOnBoard) && ((isWhite && pieces[newRow][newCol] <= 0) || (!isWhite && pieces[newRow][newCol] >= 0)))
								addMove(piece, row, col, newRow, newCol, possibleMoves);
						// if a piece goes off the board or is blocked (by either color), stop checking that path
						} while (lastWasOnBoard && (pieces[newRow][newCol] == EMPTY));
					}

					break;
				case QUEEN:
					// queen simply uses the logic of the rook AND the bishop

					// PASTED FROM ROOK
					for (int direction = 0; direction < 4; direction++)
						{
							bool lastWasOnBoard;
							newCol = col; newRow = row;	// reset starting points
							do
							{
								// iterates through N, S, E, W
								switch (direction)
								{
								case 0: newRow++; break;	// NORTH
								case 1: newRow--; break;	// SOUTH
								case 2: newCol++; break;	// EAST
								case 3: newCol--; break;	// WEST
								}

								// add move if:
								// 1) square is on the board AND
								// 2) square is empty OR occupied by OPPOSITE color
								lastWasOnBoard = onBoard(newRow, newCol);
								if ((lastWasOnBoard) && ((isWhite && pieces[newRow][newCol] <= 0) || (!isWhite && pieces[newRow][newCol] >= 0)))
									addMove(piece, row, col, newRow, newCol, possibleMoves);
							// if a piece goes off the board or is blocked (by either color), stop checking that path
							} while (lastWasOnBoard && (pieces[newRow][newCol] == EMPTY));
						}
					// PASTED FROM BISHOP
					for (int north = 0; north <=1; north++)
						for (int east = 0; east <=1; east++)
						{
							bool lastWasOnBoard;
							newCol = col; newRow = row;	// reset starting points
							do
							{
								// iterates through NE, SE, SW, and NW directions
								if (north) newCol++;
								else newCol--;
								if (east) newRow++;
								else newRow--;

								// add move if:
								// 1) square is on the board AND
								// 2) square is empty OR occupied by OPPOSITE color
								lastWasOnBoard = onBoard(newRow, newCol);
								if ((lastWasOnBoard) && ((isWhite && pieces[newRow][newCol] <= 0) || (!isWhite && pieces[newRow][newCol] >= 0)))
									addMove(piece, row, col, newRow, newCol, possibleMoves);
							// if a piece goes off the board or is blocked (by either color), stop checking that path
							} while (lastWasOnBoard && (pieces[newRow][newCol] == EMPTY));
						}

					break;
				case KING:
					for (int rowAdd = -1; rowAdd <= 1; rowAdd++)
						for (int colAdd = -1; colAdd <= 1; colAdd++)
						{
							if (row || col)		// not looking at (0, 0) ... king can't "move" to where he started
							{
								newRow = row + rowAdd;
								newCol = col + colAdd;
								// add move if:
								// 1) square is on the board AND
								// 2) square is empty OR occupied by OPPOSITE color
								if (onBoard(newRow, newCol) && ((isWhite && pieces[newRow][newCol] <= 0) || (!isWhite && pieces[newRow][newCol] >= 0)))
									addMove(piece, row, col, newRow, newCol, possibleMoves);
							}
						}

					break;
				}
			}
	
}

bool Board::canCastle(bool playerIsWhite, bool kingside)
{
	if ((playerIsWhite && kingside && !whiteCanCastleKingside) ||
			(playerIsWhite && !kingside && !whiteCanCastleQueenside) ||
			(!playerIsWhite && kingside && !blackCanCastleKingside) ||
			(!playerIsWhite && !kingside && !blackCanCastleQueenside))
		return false;

	// if player hasn't lost ability to castle with these
	// pieces yet, check if it is legal

	// each side is symmetrical
	int row;
	if (playerIsWhite)
		row = 0;
	else
		row = 7;

	if (kingside)
	{
		if (!((pieces[row][5] == EMPTY) && (pieces[row][6] == EMPTY)))		// can't castle with something in king's path
			return false;
		for (int col = 4; col < 8; col++)		// see if king is in, or passes through check
		{
			if (isInCheck(row, col, playerIsWhite))
				return false;
		}
	}
	else
	{
		if (!((pieces[row][1] == EMPTY) && (pieces[row][2] == EMPTY) &&		// can't castle with something in king's path
		(pieces[row][3] == EMPTY)))
			return false;
		for (int col = 4; col >= 0; col--)		// see if king is in, or passes through check
		{
			if (isInCheck(row, col, playerIsWhite))
				return false;
		}
	}
//	if (verbose)
	{
		cout << ((playerIsWhite) ? "White" : "Black") << " CAN CASTLE------------>\n";
		d(kingside); d(whiteCanCastleKingside); d(whiteCanCastleQueenside);
		printBoard();
	}
	return true;
}

/*
 * Performs the castle move on this Board
 */
void Board::castle(bool playerIsWhite, bool kingside)
{
	int row;
	// castles must occur in row 1 for white, row 8 for black
	if (playerIsWhite)
		row = 0;
	else
		row = 7;

	// castling is symmetrical
	if (kingside)
	{
		// move king
		pieces[row][6] = pieces[row][4];
		pieces[row][4] = EMPTY;

		// move rook
		pieces[row][5] = pieces[row][7];
		pieces[row][7] = EMPTY;
	}
	else
	{
		// move king
		pieces[row][2] = pieces[row][4];
		pieces[row][4] = EMPTY;

		// move rook
		pieces[row][3] = pieces[row][0];
		pieces[row][0] = EMPTY;
	}
	if (playerIsWhite)
		whiteHasCastled = true;
	else
		blackHasCastled = true;
	if (verbose)
		cout << "CASTLING************\n";
}


/*
 * Based on code from generateMoves()
 * returns true if player with color
 * playerColor is in check on Board
 */
bool Board::isInCheck(int playerColor)
{
	bool playerIsWhite = (playerColor > 0);

    // find where the player's king is
    int kingValue = KING * ((playerIsWhite) ? 1 : -1);
    int kingRow = -1, kingCol = -1;		// -1 marks that we haven't located it yet
    for (int row = 0; kingRow < 0 && row < 8; row++)
		for (int col = 0; kingRow < 0 && col < 8; col++)
		{
			if (pieces[row][col] == (kingValue))	// found the king
			{
				kingRow = row;		// store location
				kingCol = col;
			}
		}
    return isInCheck(kingRow, kingCol, playerIsWhite);
}

/*
 * returns true if piece at kingRow, kingCol is in
 * check (can be taken by piece of opposite of playerColor)
 */
bool Board::isInCheck(int kingRow, int kingCol, bool playerIsWhite)
{
	int newRow, newCol; // store each new move being examined

	/*
	 * PAWN
	 */
	for (int left = 0; left <= 1; left++)
	{
		newCol = kingCol + (1 * ((left) ? -1 : 1));	// look at square diagonal and to the left, or right

		// the directions are reversed here for black and white
		// compared to moveGen since it is from the King's perspective (and this is what we want)
		if (playerIsWhite)
			newRow = kingRow + 1;
		else
			newRow = kingRow - 1;

		if (onBoard(newRow, newCol) && (abs(pieces[newRow][newCol]) == PAWN))
		{ // if there is an opponent's piece in that square, king is in check
			if ((playerIsWhite && pieces[newRow][newCol] < 0) || (!playerIsWhite
					&& pieces[newRow][newCol] > 0))
				return true;
		}
	}
	/*
	 * KNIGHT
	 */

	// for each direction:
	for (int north = 0; north <= 1; north++)
		for (int east = 0; east <= 1; east++)
			// knights move by 2 in a column and 1 in a row, or vice versa
			// columnBy2 represents which of these options we're trying
			for (int columnBy2 = 0; columnBy2 <= 1; columnBy2++)
			{
				int addToCol = ((columnBy2) ? 2 : 1);
				int addToRow = ((columnBy2) ? 1 : 2);
				if (north)
					newRow = kingRow + addToRow;
				else
					newRow = kingRow - addToRow;
				if (east)
					newCol = kingCol + addToCol;
				else
					newCol = kingCol - addToCol;
				// king is in check if:
				// 1) square is on the board AND
				// 2) square is occupied by a knight of the OPPOSITE color
				if (onBoard(newRow, newCol) && (abs(pieces[newRow][newCol]) == KNIGHT)
						&& ((playerIsWhite && pieces[newRow][newCol] < 0)
								|| (!playerIsWhite && pieces[newRow][newCol] > 0)))
					return true;
			}

	/*
	 * ROOK (and QUEEN)
	 */
	for (int direction = 0; direction < 4; direction++)
	{
		bool lastWasOnBoard;
		newCol = kingCol;
		newRow = kingRow; // reset starting points
		do
		{
			// iterates through N, S, E, W
			switch (direction)
			{
			case 0:
				newRow++;
				break; // NORTH
			case 1:
				newRow--;
				break; // SOUTH
			case 2:
				newCol++;
				break; // EAST
			case 3:
				newCol--;
				break; // WEST
			}

			// king in check if:
			// 1) square is on the board AND
			// 2) square is occupied by queen or rook of OPPOSITE color
			lastWasOnBoard = onBoard(newRow, newCol);
			if ((lastWasOnBoard) && ((abs(pieces[newRow][newCol]) == ROOK) || (abs(pieces[newRow][newCol]) == QUEEN)) &&
					((playerIsWhite && pieces[newRow][newCol] < 0) ||
							(!playerIsWhite && pieces[newRow][newCol] > 0)))
				return true;
			// if a piece goes off the board or is blocked (by either color), stop checking that path
		} while (lastWasOnBoard && (pieces[newRow][newCol] == EMPTY));
	}

	/*
	 * BISHOP (includes QUEEN)
	 */
	for (int north = 0; north <= 1; north++)
		for (int east = 0; east <= 1; east++)
		{
			bool lastWasOnBoard;
			newCol = kingCol;
			newRow = kingRow; // reset starting points
			do
			{
				// iterates through NE, SE, SW, and NW directions
				if (north)
					newCol++;
				else
					newCol--;
				if (east)
					newRow++;
				else
					newRow--;

				// king in check if:
				// 1) square is on the board AND
				// 2) square is occupied by queen or bishop of OPPOSITE color
				lastWasOnBoard = onBoard(newRow, newCol);
				if ((lastWasOnBoard) && ((abs(pieces[newRow][newCol]) == BISHOP) || (abs(pieces[newRow][newCol]) == QUEEN))
						&& ((playerIsWhite && pieces[newRow][newCol] < 0)
								|| (!playerIsWhite && pieces[newRow][newCol] > 0)))
					return true;
				// if a piece goes off the board or is blocked (by either color), stop checking that path
			} while (lastWasOnBoard && (pieces[newRow][newCol] == EMPTY));
		}
	/*
	 * KING
	 */
	for (int rowAdd = -1; rowAdd <= 1; rowAdd++)
		for (int colAdd = -1; colAdd <= 1; colAdd++)
		{
			if (kingRow || kingCol) // not looking at (0, 0) ... king can't "move" to where he started
			{
				newRow = kingRow + rowAdd;
				newCol = kingCol + colAdd;
				// king in check if:
				// 1) square is on the board AND
				// 2) square is occupied by king of OPPOSITE color
				if (onBoard(newRow, newCol) && (abs(pieces[newRow][newCol]) == KING)
						&& ((playerIsWhite && pieces[newRow][newCol] < 0)
								|| (!playerIsWhite && pieces[newRow][newCol] > 0)))
					return true;
			}
		}
	return false;
}

bool Board::operator==(const Board& other)
{
    for(int i=0; i<8; i++)
        for(int j=0; j<8; j++)
        {
            if(this->pieces[i][j] != other.pieces[i][j])
                return false;
        }
    if(
    blackCanCastleQueenside != other.blackCanCastleQueenside ||
    blackCanCastleKingside != other.blackCanCastleKingside ||
    whiteCanCastleQueenside != other.whiteCanCastleQueenside ||
    whiteCanCastleKingside != other.whiteCanCastleKingside ||
    whiteHasCastled != other.whiteHasCastled ||
    blackHasCastled != other.blackHasCastled
    )
        return false;
    return true;
}
